/*
 * Copyright (c) 2017-2019, AEye, Inc.
 * All rights reserved.
 */

#ifndef AEYECLIENTS_SENSORDEV_H
#define AEYECLIENTS_SENSORDEV_H

#include "AEyeSensorAPI.h"
#include "AEyeAPIConfig.hpp"
#include "Sensor.hpp"
#include "HawkeyeFrame.hpp"

namespace aeye {
  class SensorCommander;
}

struct HawkeyePortConfig {
  uint16_t client = aeye::DEFAULT_CLIENT_HAWKEYE_PORT;
};


class SensorDev final : public aeye::Sensor {
  private:
    bool _selected{};
    bool _isManualMode{};
    uint16_t _hawkEyePort;
    uint16_t _serverHawkEyePort;
    bool hawkeyeOn{};
    bool     useJumboPackets{};
    uint16_t lidarPacketSize{};
    void ensureHawkeyeOn();
    void ensureHawkeyeOn(bool enable);
  public:
    SensorDev(aeye::SensorConfig sensor_config, aeye::DataPortConfig data_ports, HawkeyePortConfig hawkeye_ports,
              std::string net_interface, std::string sensor_ip, std::string sensor_name);
    bool isSelected() const;
    void setSelected(bool selected);
    void toggleManualMode(bool manualMode);
    void toggleScanningMode(bool scanningMode);
    void writeScannerRegister(uint32_t addr, uint32_t value);
    uint32_t readScannerRegister(uint32_t addr);
    void writeReceiverRegister(uint32_t addr, uint32_t value);
    uint32_t readReceiverRegister(uint32_t addr);
    void start() override;
    void setLaserEnable(uint8_t enable);

    void setHawkEyeCallback(const std::function<void(aeye::HawkeyeFrame&&)>& processCallback);
    void startHawkEye();
    void stopHawkEye();
    void toggleHawkEye(bool enable, const std::string& clientIPAddress, uint16_t port);
    uint16_t getHawkEyePort() const noexcept;
    uint16_t getServerHawkEyePort() const noexcept;
    void sendHawkEyePoint(bool enable, uint16_t row, uint16_t col);
    void toggleARxSweepMode(bool enable, aeye::GainChannel gain_channel, aeye::PixelMode pixel_mode, uint16_t colSize, uint16_t rowSize);
    void toggleARxStaticMode(bool enable, aeye::PixelMode pixel_mode, uint32_t row, uint32_t col);
    void generateARxLUTV2(aeye::RxFOV rxFov, aeye::PixelMode pixelMode, uint8_t rxWindowSize);
    void getGenerateARxLutV2Status(bool &isRunning,
                                   uint8_t &calIterations,
                                   uint8_t &startScore,
                                   uint64_t &endScore,
                                   float &ratio);
    /**
    * @brief Returns Hawkeye buffer on the Hawkeye Port.
    * @param frameCount: Specify the number of frames to return
    */
    void getHawkeyeBuffer(uint32_t frameCount=1);

    /*
     * Enables changing ARx pixel dynamically from the client
     * @param col: Rx col (0-127)
     * @param row: Rx row (0-63)
     * @param pixelMode: Rx pixel mode (0=1x1; 1=2x2; 2=3x3)
     */
    void setARxPixel(uint8_t col, uint8_t row, uint8_t pixelMode);

    void setPoseInPcapMode(aeye::Pose pose);
    void setShotlistNameInPcapMode(const std::string& shotlist_name);

    /// @brief Sends a set of horizontal zone parameters for the sensor from which it will construct a Range Point List
    void sendScanZoneParameters(std::vector<aeye::AdvancedZoneScanRegion>&);

    void killSensorService();

    bool isHawkeyeOn() const noexcept;

    uint8_t getScanPatternFlags() const noexcept;
    uint32_t getScanblockId() const noexcept;
    const std::string& getMacAddress() const noexcept;

    void setRxFOV(aeye::RxFOV rx_fov);

    /**
    * @brief Set laser power.
    * @param value Laser power. A percentage of maximum laser power, from 0-100%.
    */
    void sendLaserPower(float value);

    aeye::HsyncParameters getHsyncParams();

};

#endif //AEYECLIENTS_SENSORDEV_H
